package org.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.config.annotation.*;
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 此配置有问题， 主要是这里  setHeartbeatValue(new long[] {13000, 17000}); 双向心跳，会引起 粘包，从而引起协议解析错误
 */
//@Configuration
//@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    // 配置 STOMP 层心跳(应用层)
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 配置消息代理
        config.enableSimpleBroker("/topic")
              // 配置心跳设置
              .setTaskScheduler(heartbeatScheduler())
                //[server->client,client->server]
//              .setHeartbeatValue(new long[] {13000, 17000}); // 心跳间隔
                .setHeartbeatValue(new long[] {0, 17000}); // 心跳间隔
        
        // 设置应用程序前缀
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                // 允许跨域
                .setAllowedOriginPatterns("*");
                // 启用SockJS回退
//                .withSockJS();
                // 设置心跳时间（毫秒）
                //.setHeartbeatTime(10000); // 10秒心跳间隔
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration){
//        registration.setSendTimeLimit(10*1000)// 发送
//                .setTimeToFirstMessage(15*1000)  ;//首次
        registration.addDecoratorFactory(pingDecoratorFactory());
    }



//    @Bean
//    public ServletServerContainerFactoryBean createWebSocketContainer() {
//        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
//
////        container.setMaxSessionIdleTimeout(20*1000L);//20s => 25s  //起作用，空闲20秒后，会断开
//        container.setMaxSessionIdleTimeout(100*1000L);//100s => 112s
//        container.setAsyncSendTimeout(Duration.ofSeconds(10).toMillis());
//        container.setMaxBinaryMessageBufferSize(1024 * 1024);
//
//        return container;
//    }

    // 3. 监听原生 WebSocket 断开
    @Bean
    public WebSocketHandlerDecoratorFactory webSocketHandlerDecoratorFactory() {
        return handler -> new WebSocketHandlerDecorator(handler) {
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
                System.out.println("[原生] 连接断开: " + session.getId() + ", 原因: " + closeStatus);
                super.afterConnectionClosed(session, closeStatus);
            }
        };
    }


    // 心跳调度器
    private ThreadPoolTaskScheduler heartbeatScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(1);
        scheduler.setThreadNamePrefix("ws-heartbeat-thread-");
        scheduler.initialize();
        return scheduler;
    }

    @Bean
    public WebSocketHandlerDecoratorFactory pingDecoratorFactory() {
//        return handler -> new WebSocketHandlerDecorator(handler) {
//            private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
//
//            @Override
//            public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//                System.out.println("in afterConnectionEstablished");
//                scheduler.scheduleAtFixedRate(() -> {
//                    if(session.isOpen()) {
//                        try {
//                            session.sendMessage(new PingMessage());
//                            System.out.println("Sent WebSocket Ping to " + session.getId());
//                        } catch (IOException e) {
//                            System.err.println("Ping failed: " + e.getMessage());
//                            throw new RuntimeException(e);
//                        }
//                    }
//                }, 10, 10, TimeUnit.SECONDS); // 每10秒发送一次
//                super.afterConnectionEstablished(session);
//            }
//
//            @Override
//            public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
//                scheduler.shutdown();
//                super.afterConnectionClosed(session, status);
//            }
//        };
        return handler -> new WebSocketHandlerDecorator(handler) {
            // 使用volatile确保线程可见性
            private volatile ScheduledExecutorService scheduler;

            @Override
            public void afterConnectionEstablished(WebSocketSession session) throws Exception {
                // 创建单线程调度器（每个连接独立）
                scheduler = Executors.newSingleThreadScheduledExecutor(
                        new ThreadFactory() {
                            private final AtomicInteger count = new AtomicInteger(0);

                            @Override
                            public Thread newThread(Runnable r) {
                                Thread thread = new Thread(r);
                                thread.setName("ws-ping-" + count.incrementAndGet());
                                thread.setDaemon(true); // 设置为守护线程
                                return thread;
                            }
                        });

                // 启动心跳任务
                scheduler.scheduleAtFixedRate(() -> {
                    try {
                        if (session.isOpen()) {
                            session.sendMessage(new PingMessage());
                            System.out.println("Sent Ping to " + session.getId());
                        }
                    } catch (IOException e) {
                        System.err.println("Ping error: " + e.getMessage());
                        try {
                            session.close(CloseStatus.SESSION_NOT_RELIABLE);
                        } catch (IOException ex) {
                            // 忽略关闭异常
                        }
                    }
                }, 10, 10, TimeUnit.SECONDS);

                super.afterConnectionEstablished(session);
            }

            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
                // 优雅关闭线程池
                if (scheduler != null) {
                    scheduler.shutdownNow();
                    try {
                        if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
                            System.err.println("Ping scheduler shutdown timeout");
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                super.afterConnectionClosed(session, status);
            }
        };
    }

    // STOMP心跳监控
    @EventListener
    public void handleStompConnected(SessionConnectedEvent event) {
        System.out.println("in handleStompConnected event "+event);
        StompHeaderAccessor headers = StompHeaderAccessor.wrap(event.getMessage());
        System.out.println("STOMP心跳配置: " + Arrays.toString(headers.getHeartbeat()));
    }

    // 监听连接断开事件（可能由心跳超时引起）
    @EventListener
    public void handleDisconnect(SessionDisconnectEvent event) {
        if (event.getCloseStatus() == CloseStatus.SESSION_NOT_RELIABLE) {
            System.out.println("STOMP心跳丢失导致断开: " + event.getSessionId());
        }
    }

//    // 监听心跳实际发送（需要自定义心跳拦截器）
//    @EventListener
//    public void handleOutboundHeartbeat(MessageSentEvent event) {
//        if (event.getMessage().getHeaders().get("stompCommand") == StompCommand.HEARTBEAT) {
//            System.out.println("STOMP心跳已发送");
//        }
//    }


}